﻿Imports System.Runtime.InteropServices

Namespace Widgets

    Delegate Sub TaskTimer_UpdateDelegate(ByVal Elapsed As TimeSpan, ByVal IsUserIdle As Boolean)

    Public Class TaskTimer(Of TView As {ITaskTimerView, Control})
        Inherits WidgetBase(Of TView)

        Private m_UserIdleTimer As New System.Timers.Timer(1000)
        Private m_Timer As New System.Timers.Timer(1000)
        Private m_TimeSpan As New TimeSpan(0)
        Private m_IsUserIdle As Boolean = False

        Public Event Update(ByVal Elapsed As TimeSpan, ByVal IsIdle As Boolean)

        Public Sub New(ByVal View As TView)
            MyBase.New(View)
            AddHandler m_Timer.Elapsed, AddressOf m_Timer_Elapsed
            AddHandler m_UserIdleTimer.Elapsed, AddressOf m_UserIdleTimer_Elapsed
            m_UserIdleTimer.Start()
        End Sub

#Region " Interop "

        Shared Function GetLastInputInfo(ByRef plii As LASTINPUTINFO) As Boolean
        End Function

        <StructLayout(LayoutKind.Sequential)> _
      Structure LASTINPUTINFO
            <MarshalAs(UnmanagedType.U4)> _
            Public cbSize As Integer
            <MarshalAs(UnmanagedType.U4)> _
            Public dwTime As Integer
        End Structure

        Dim m_idletime As Integer
        Dim m_lastInputInf As New LASTINPUTINFO()

        Public Function GetLastInputTime() As Integer
            m_idletime = 0
            m_lastInputInf.cbSize = Marshal.SizeOf(m_lastInputInf)
            m_lastInputInf.dwTime = 0
            If GetLastInputInfo(m_lastInputInf) Then
                m_idletime = Environment.TickCount - m_lastInputInf.dwTime
            End If
            If m_idletime > 0 Then
                Return m_idletime / 1000
            Else
                Return 0
            End If
        End Function

#End Region

        Public Sub Start(ByVal StartingValue As TimeSpan)
            m_TimeSpan = StartingValue
            m_Timer.Start()
        End Sub

        Public Sub [Stop]()
            View.OnTaskTimer_Stop(m_TimeSpan)
        End Sub

        Private Sub m_Timer_Elapsed()
            If Not m_IsUserIdle Then m_TimeSpan.Add(New TimeSpan(0, 0, 1))
            UpdateFromTimers(m_TimeSpan, m_IsUserIdle)
        End Sub

        Private Sub m_UserIdleTimer_Elapsed()
            If GetLastInputTime() > 300 Then
                m_IsUserIdle = True
            Else
                m_IsUserIdle = False
            End If
        End Sub

        Private Sub UpdateFromTimers(ByVal Elapsed As TimeSpan, ByVal IsUserIdle As Boolean)
            If View.InvokeRequired Then
                View.Invoke(New TaskTimer_UpdateDelegate(AddressOf UpdateFromTimers), Elapsed, IsUserIdle)
            Else
                RaiseEvent Update(Elapsed, IsUserIdle)
            End If
        End Sub

    End Class

End Namespace